package com.game.client;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.concurrent.LinkedBlockingQueue;

import com.game.share.IOPackage;
import com.game.share.RPCCallback;
import com.game.share.StreamReader;
import com.game.share.StreamWriter;

public class Client implements Runnable {

	class Request {
		Request(IOPackage input, RPCCallback callback) {
			this.input = input;
			this.callback = callback;
		}
		final IOPackage input;
		final RPCCallback callback;
	}

	LinkedBlockingQueue<Request> requestQueue;

	boolean isClose;

	final String host;

	public Client(String host) {
		isClose = false;
		this.host = host;
		requestQueue = new LinkedBlockingQueue<Client.Request>();
	}

	public void close() {
		isClose = true;
		sendHeartBreak();
	}

	@Override
	public void run() {
		Socket socket = new Socket();
		try {
			SocketAddress address = new InetSocketAddress(
					InetAddress.getByName(host), 6666);
			socket.connect(address, 1000);
			StreamReader reader = new StreamReader(socket.getInputStream());
			StreamWriter writer = new StreamWriter(socket.getOutputStream());
			while (!isClose) {
				Request request = take();
				writer.writePackage(request.input);
				writer.flush();
				processPKG(reader.readPackage(), request);
			}
			reader.close();
			writer.close();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			System.out.println("client close");
		}
	}

	private Request take() {
		try {
			return requestQueue.take();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return null;
	}

	private void processPKG(IOPackage output, Request request) {
		if (request.callback != null) {
			request.callback.onSuccess(output);
		}
	}

	private void sendHeartBreak() {
		try {
			send(ActionGenerator.getHeartBreakAction(), null);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void send(IOPackage pkg, RPCCallback callback) {
		requestQueue.add(new Request(pkg, callback));
	}

	public IOPackage send(IOPackage pkg) {
		StatedCallback callback = new StatedCallback();
		requestQueue.add(new Request(pkg, callback));
		while (!callback.isBack())
			sleep(10);
		System.out.println("client : receive feed back");
		return callback.getResult();
	}

	private void sleep(long time){
		try {
			Thread.sleep(time);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
}
